<?php
/**
 * <pre>
 * <b>RUBIK IT Solution & Development ltd.</b>
 *
 * PROJECT      : rubik-base
 * COPYRIGHT    : 2008
 * ------------------------------------------------------
 * 
 * [GENERAL INFO OF THIS FILE] 
 *
 * </pre>
 * 
 * @version 		1.5
 * @author			Dang Nhon Hoa <HoaDN@rubik.com.vn>
 * @access			public
 * @package			rubik.base.dbo
 *
 * Created on	: May 5, 2008
 */
RCoreImporter::cls("dbo.AbstractRubikDBObject" );

/**
 * The abstract class of RUBIK for management the Database Transfer Object
 *
 */
class AbstractRubikDTO extends AbstractRubikDBObject {
	
	/**
	 * Constructor
	 *
	 * @param string $from this can be a from clause of just table name.
	 * @param string $where the where clause of this dbo
	 * @param string $orderBy the ORDER BY clause
	 * @param Database $db database object of this DB Info.
	 */
	function __construct($from = '', $where = '', $orderBy = '', $db = null) {
		parent::__construct ( $from, $where, $orderBy, $db );
	}
	
	/**
	 * Create the Update clause of this DB Object
	 *
	 * @param boolean $ignoreNull update with null values or not
	 * @param string $where where to update. if not --> default where and key
	 * @return string SQL string
	 */
	function createUpdateSQL($ignoreNull = true, $where = '') {
		$this->prepareData ();
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		return $dbInfo->createUpdateSQL ( $this, $ignoreNull, $where );
	}
	
	/**
	 * Create the Insert clause of this DB Object
	 *
	 * @param boolean $ignoreNull update with null values or not
	 * @return string SQL string
	 */
	function createInsertSQL($ignoreNull = true) {
		$this->prepareData ();
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		return $dbInfo->createInsertSQL ( $this, $ignoreNull );
	}
	
	/**
	 * Check if the key is not exists -> create Insert SQL
	 * Else -> create update SQL
	 *
	 * @return string SQL
	 */
	function createChangeSQL($ignoreNull = true) {
		
		if ($this->checkKeyNotDefault ()) {
			return $this->createUpdateSQL ( $ignoreNull );
		}
		
		return $this->createInsertSQL ( $ignoreNull );
	}
	
	/**
	 * Check if key value is not default value.
	 *
	 * @param AbstractRubikDBObject $rubikDBO
	 * @return boolean
	 */
	function checkKeyNotDefault($withPrepareData = true) {
		if ($withPrepareData) {
			$this->prepareData ();
		}
		// Check if key value is not default value.
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$keyField = $dbInfo->getKeyField ();
		$keyName = $keyField->fieldName;
		if ($this->$keyName == $keyField->defaultValue) {
			return false;
		}
		return true;
	}
	
	/**
	 * Create select clause with key
	 * if the key is specify (not default value) then the SELECT clause will be created
	 *
	 * @return string/null null if key value is default value of key
	 */
	function createSelectSQLWithKey() {
		// if key equal to default --> this is not the needed
		if (! $this->checkKeyNotDefault ()) {
			return null;
		}
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$keyField = $dbInfo->getKeyField ();
		$keyName = $keyField->fieldName;
		$keyValue = $this->$keyName;
		
		$keyName = $dbInfo->dbQuoteField ( $keyName );
		$keyValue = $dbInfo->dbQuoteData ( $keyValue );
		
		$extWhere = "{$keyName} = {$keyValue}";
		return $this->getSelectSQL ( true, $extWhere );
	}
	
	/**
	 * Set value for the key
	 *
	 * @param mixed $value
	 */
	function setKeyValue($value) {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$keyField = $dbInfo->getKeyField ();
		$keyName = $keyField->fieldName;
		$this->$keyName = $value;
	}
	
	/**
	 * Get the key value
	 *
	 * @return mixed
	 */
	function getKeyValue() {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$keyField = $dbInfo->getKeyField ();
		$keyName = $keyField->fieldName;
		return $this->$keyName;
	}
	
	/**
	 * Check valid data
	 * CAUTION: this function shoud be override by the sub class
	 *
	 * @return boolean
	 */
	function checkValidData() {
		
		$result = $this->checkUnique ();
		if ($result !== true) {
			return false;
		}
		// if edit then we don't check any thing
		if ($this->checkKeyNotDefault ()) {
			return true;
		}
		
		// if new then check the mandatory values
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$result = $dbInfo->checkMandatory ( $this );
		if ($result === true) {
			return true;
		}
		foreach ( $result as $err ) {
			$this->_errors [] = SysLanguage::_ ( "{$err}_must_have" );
		}
		return false;
	}
	
	/**
	 * Check valid data
	 * CAUTION: this function shoud be override by the sub class
	 *
	 * @return boolean
	 */
	function checkUnique() {
		$this->prepareData ();
		// if new then check the mandatory values
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$result = $dbInfo->checkUnique ( $this );
		if ($result === true) {
			return true;
		}
		$this->_errors = $result;
		return false;
	}
	
	/**
	 * Create the delete SQL
	 *
	 * @param int/array $idOrArrayId
	 * @return string
	 */
	function createDeleteSQL($idOrArrayId = null) {
		if ($idOrArrayId === null) {
			if (! $this->checkKeyNotDefault ()) {
				return false;
			}
			$idOrArrayId = $this->getKeyValue ();
		}
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		return $dbInfo->createDeleteSQL ( $idOrArrayId, $this );
	}
	
	/**
	 * Insert into database if the value of $fieldToCheck in this DTO is not existing
	 *
	 * @param string $checkFieldOrArrayFields
	 * @return mix 
	 */
	function insertIfNotExist($checkFieldOrArrayFields) {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$this->prepareData ();
		if ($dbInfo->checkExisting ( $this, $checkFieldOrArrayFields )) {
			return false;
		}
		
		$db = $dbInfo->getDatabase ();
		return $db->saveDTO ( $this );
	}
	
	/**
	 * Insert or Update, Check if all field in the list is existed -> update
	 * else insert
	 *
	 * @param string/array $fieldOrArrayFields
	 * @return mix false mean update or error on insert. Otherwise it's DTO that saved.
	 */
	function upsert($fieldOrArrayFields) {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$this->prepareData ();
		
		$db = $dbInfo->getDatabase ();
		if ($dbInfo->checkExisting ( $this, $fieldOrArrayFields )) {
			$where = $dbInfo->createWhereCheckExist ( $this, $fieldOrArrayFields );
			$db->updateDTO ( $this, $where );
			return false;
		}
		
		return $db->insertDTO ( $this );
	}
	
	/**
	 * Increase the value of $increaseField inside this DTO up $increaseStep 
	 *
	 * @param string $increaseField
	 * @param int $increaseStep
	 * @return int increased number
	 */
	function increaseVal($increaseField, $increaseStep = 1) {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		return $dbInfo->increaseVal ( $this, $increaseField, $increaseStep );
	}
	
	/**
	 * Insert or Update, Check if all field in the list is existed -> update
	 * else insert
	 *
	 * @param string/array $fieldOrArrayFields
	 * @param boolean $fillBack should fill back data if exist?
	 * @return mix 
	 */
	function checkExisting($fieldOrArrayFields, $fillBack = false) {
		$dbInfo = RubikDBFactory::getDBInfo ( $this );
		$this->prepareData ();
		
		$result = $dbInfo->checkExisting ( $this, $fieldOrArrayFields, $fillBack );
		$this->setPreparedData ( false ); //TODO please check for this case
		return $result;
	}
}
?>
